import java.util.Scanner;
import java.util.TreeSet;

public class Test {


    //最长回文子序列
    //给定一个字符串，找到其中最长的回文子序列，并返回该序列的长度。
    //注：回文序列是指这个序列无论从左读还是从右读都是一样的。
    //本题中子序列字符串任意位置删除k（len(s)>=k>=0）个字符后留下的子串
    //数据范围：字符串长度满足1≤n≤1000
    //进阶：空间复杂度O(n2) ， 时间复杂度O(n2)
    //输入描述：
    //输入一个字符串
    //输出描述：
    //输出最长回文子序列
    //示例1
    //输入：
    //abccsb
    //输出：
    //4
    //说明：
    //分别选取第2、3、4、6位上的字符组成“bccb”子序列是最优解
    //示例2
    //输入：
    //abcdewa
    //输出：
    //3
    //说明：
    //分别选取第一个和最后一个a，再取中间任意一个字符就是最优解
    //算法思路：
    //基础的区间 dp 问题：
    //1. 状态表⽰： dp[i][j] 表⽰：字符串 [i, j] 范围内的最⻓回⽂⼦序列的⻓度；
    //2. 状态转移⽅程：
    //◦ 当 i == j 的时候，只有⼀个字符，⻓度为 1；
    //◦ 当 i < j 的时候，分情况讨论：
    //▪ s[i] == s[j]：dp[i][j] = dp[i + 1][j - 1];
    //▪ s[i] != s[j]：dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])；
    //3. 返回值： dp[0][n - 1] 。
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        char[] s = in.next().toCharArray();
        int n = s.length;
        int[][] dp = new int[n][n];
        for (int i = n-1; i >= 0; i--) {
            dp[i][i] = 1;
            for (int j = i+1; j < n; j++) {
                if (s[i] == s[j]){
                    dp[i][j] = dp[i+1][j-1]+2;
                }else{
                    dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]);
                }
            }
        }
        System.out.println(dp[0][n-1]);
    }




    //集合排序
    //给你两个集合，要求{A} + {B}。 注：同一个集合中不会有两个相同的元素。
    //输出时按数字升序输出。
    //数据范围：1≤n,m≤10000 ，集合中的元素满足1≤val≤10^5
    //输入描述：
    //每组输入数据分为三行,第一行有两个数字n,m，分别表示集合A和集合B的元素个数。
    // 后两行分别表示集合A和集合B。每个元素为不超过int范围的整数,每个元素之间有个空格隔开。
    //输出描述：
    //针对每组数据输出一行数据，表示合并后的集合，要求从小到大输出，
    // 每个元素之间有一个空格隔开,行末无空格。
    //示例1
    //输入：
    //3 3
    //1 3 5
    //2 4 6
    //输出：
    //1 2 3 4 5 6
    //示例2
    //输入：
    //2 2
    //1 2
    //1 2
    //输出：
    //1 2
    public static void main2(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        TreeSet<Integer> set = new TreeSet<>();
        int x;
        while (n-- != 0){
            x = in.nextInt();
            set.add(x);
        }
        while(m-- != 0){
            x = in.nextInt();
            set.add(x);
        }
        for (int a: set) {
            System.out.print(a +" ");
        }
    }



    //爱丽丝的人偶
    //链接：https://ac.nowcoder.com/acm/problem/213471
    //来源：牛客网
    //爱丽丝有n 个人偶，每个人偶的身高依次是1、2、3……n
    //现在她要将这n 个人偶摆成一排。
    //但是人偶被设置了魔法。假设对一个非两端的（不在队首也不在队尾）人偶x 而言，
    // 她相邻的两个人偶，一个比x 高、一个比x 矮，那么x 就会爆炸。
    //爱丽丝想找到一种摆法，使得所有人偶都不会爆炸。你能帮帮她吗？
    //输入描述:
    //一个正整数(3≤n≤100000)
    //输出描述:
    //满足要求的一种摆法。如果有多解，输出任意一种摆法即可。
    //示例1
    //输入
    //3
    //输出
    //1 3 2
    //说明
    //对于第二个人偶，她两边的两个人偶都比她矮，满足要求。
    //另外，[3 1 2]、 [2 1 3] 、[2 3 1]这三种摆法也都满足要求。输出这三种摆法也视为正确。
    public static void main1(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();

        int l = 1;
        int r = n;
        while(l<=r){
            System.out.println(l+" ");
            l++;
            if (l<=r){
                System.out.println(r + " ");
                r--;
            }
        }
    }

}
